﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Natars
{
    /// <summary>
    /// Логика взаимодействия для Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            _outputLb.ItemsSource = _natars;
        }
        private readonly ObservableCollection<NatarDist> _natars = new ObservableCollection<NatarDist>();
        private void SrcTxtChanged(object sender, TextChangedEventArgs e)
        {
            var nat = Parse(_sourceTb.Text);
            IEnumerable<NatarDist> d;
            int x, y, radmn, radmx;
            if (int.TryParse(_xTb.Text,out x)
                && int.TryParse(_yTb.Text, out y)
                && int.TryParse(_radMinTb.Text, out radmn)
                && int.TryParse(_radMaxTb.Text, out radmx))
                d = nat.Select(nd => new NatarDist() {Natar = nd, Distance = Dist(nd.X, nd.Y, x, y)})
                    .Where(nd => 0 == radmn || nd.Distance >= radmn)
                    .Where(nd => 0 == radmx || nd.Distance <= radmx)
                    .OrderBy(nd=>nd.Distance);
            else
                d = nat.Select(nd => new NatarDist() {Natar = nd, Distance = 0});
            ProfileNatars.Clear();
            ProfileNatars.AddRange(d);
            Refresh();
        }
        private static double Dist(int x, int y, int x1, int y1)
        {
            return Math.Sqrt(Math.Pow(x - x1, 2) + Math.Pow(y - y1, 2));
        }

        private static IEnumerable<NatarData> Parse(string data)
        {
            var re = new Regex(@"(?<name>.+)\s*\t\s*(?<pop>\d+)\s+\((?<x>-?\d+)\s+\|\s+(?<y>-?\d+)\)");
           
            return re.Matches(data).OfType<Match>().Select(m => new NatarData
                                                                    {
                                                                        Name = m.Groups["name"].Value.Trim(),
                                                                        X = int.Parse(m.Groups["x"].Value),
                                                                        Y = int.Parse(m.Groups["y"].Value),
                                                                        Population = int.Parse(m.Groups["pop"].Value)
                                                                    });

        }
        private static IEnumerable<NatarData> ParseFarmList(string data)
        {
            var re = new Regex(@"\t(?<name>.+)\s*\t\s*(?<pop>\d+)\s*\t\s*(?<dist>\d+\.?\d?)\s*\t\d", RegexOptions.Multiline);
            return re.Matches(data).OfType<Match>().Select(m => new NatarData
            {
                Population = int.Parse(m.Groups["pop"].Value),
                Name = m.Groups["name"].Value.Trim()
            });
        }

        private const string CoordinatesFormat = "({0}|{1})";
        private void OutMDblClck(object sender, MouseButtonEventArgs e)
        {
            var lb = sender as ListBox;
            if (null == lb) return;
            var nat = lb.SelectedItem as NatarDist;
            if (nat == null) return;
            _natars.Remove(nat);
            Clipboard.SetText(string.Format(CoordinatesFormat, nat.Natar.X,nat.Natar.Y));
        }

        private void SrcTxtMDblClck(object sender, MouseButtonEventArgs e)
        {
            _sourceTb.Text = Clipboard.GetText();
        }

        private void CurTxtMDblClck(object sender, MouseButtonEventArgs e)
        {
            _currentTb.Text = Clipboard.GetText();
        }

        private void CurTxtChanged(object sender, TextChangedEventArgs e)
        {
            var l = ParseFarmList(_currentTb.Text).ToList();
            CurrentNatars.Clear();
            CurrentNatars.AddRange(l);
            Refresh();
        }
        private class NatarDistByNameAndPopulationComparer : IEqualityComparer<NatarDist>
        {
            public bool Equals(NatarDist x, NatarDist y)
            {
                return x.Natar.Population == y.Natar.Population && x.Natar.Name.Trim() == y.Natar.Name.Trim();
            }

            public int GetHashCode(NatarDist obj)
            {
                return obj.Natar.Name.Trim().GetHashCode() ^ obj.Natar.Population;
            }
        }
        private List<NatarData> CurrentNatars = new List<NatarData>();
        private List<NatarDist> ProfileNatars = new List<NatarDist>();
        private void Refresh()
        {
            _natars.Clear();
            var res = ProfileNatars.Except(CurrentNatars.Select(nd => new NatarDist() { Natar = nd }),
                                 new NatarDistByNameAndPopulationComparer());

            foreach (var nd in res)
            {
                _natars.Add(nd);
            }

        }
    }
    internal class NatarDist
    {
        public double Distance { get; set; }
        public string DistanceStr
        {
            get { return Distance.ToString("F"); }
        }
        public NatarData Natar { get; set; }
    }
    internal class NatarData
    {
        public int X { get; set; }
        public int Y { get; set; }
        public int Population { get; set; }
        public string Name { get; set; }
    }
}
